package com.wzh.codegen.biz.util;

import com.wzh.common.general.exception.CustomerException;
import com.wzh.common.general.util.ConditionHandler;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.stereotype.Component;

import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 模板工具类
 *
 * @author wzh
 * @since 2024-01-01
 */
@Slf4j
@Component
public class TemplateUtils {

    private VelocityEngine velocityEngine;

    @PostConstruct
    public void init() {
        Properties props = new Properties();
        props.setProperty("resource.loader", "class");
        props.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        props.setProperty("input.encoding", "UTF-8");
        props.setProperty("output.encoding", "UTF-8");

        velocityEngine = new VelocityEngine(props);
        velocityEngine.init();
    }

    /**
     * 生成微服务代码文件
     */
    public Map<String, String> generateServiceFiles(Map<String, Object> variables) {
        Map<String, String> files = new HashMap<>();

        String serviceName = (String) variables.get("serviceName");
        String serviceNameCamelCase = CodegenUtils.toCamelCase(serviceName);
        variables.put("serviceNameCamelCase", serviceNameCamelCase);
        String serviceNameTo = CodegenUtils.capitalize(serviceNameCamelCase);
        variables.put("serviceNameTo", serviceNameTo);
        String packageName = (String) variables.get("packageName");
        Boolean includeApi = (Boolean) variables.get("includeApi");
        Boolean includeSwagger = (Boolean) variables.get("includeSwagger");
        Boolean includeFeign = (Boolean) variables.get("includeFeign");

        // 生成根pom.xml
        files.put(serviceName + "/pom.xml", generateFromTemplate("templates/service/pom.xml.vm", variables));

        if (Boolean.TRUE.equals(includeApi)) {
            // 生成API模块
            files.put(serviceName + "/" + serviceName + "-api/pom.xml",
                    generateFromTemplate("templates/service/api-pom.xml.vm", variables));
        }

        // 生成业务模块
        files.put(serviceName + "/" + serviceName + "-biz/pom.xml",
                generateFromTemplate("templates/service/biz-pom.xml.vm", variables));

        // 生成启动类
        String applicationPath = serviceName + "/" + serviceName + "-biz/src/main/java/" +
                packageName.replace(".", "/") + "/" + serviceNameCamelCase + "/biz/" +
                serviceNameTo + "Application.java";
        // 服务名转换驼峰
        variables.put("serviceNameTo", serviceNameTo);
        files.put(applicationPath, generateFromTemplate("templates/service/Application.java.vm", variables));

        // 生成配置文件
        files.put(serviceName + "/" + serviceName + "-biz/src/main/resources/bootstrap.yml",
                generateFromTemplate("templates/service/bootstrap.yml.vm", variables));

        if (Boolean.TRUE.equals(includeFeign)) {
            // 生成Feign客户端示例
            String feignPath = serviceName + "/" + serviceName + "-api/src/main/java/" +
                    packageName.replace(".", "/") + "/" + serviceNameCamelCase + "/api/feign/Remote" +
                    serviceNameTo + "FeignClient.java";
            files.put(feignPath, generateFromTemplate("templates/service/FeignClient.java.vm", variables));
        }

        return files;
    }

    /**
     * 生成表代码文件
     */
    public Map<String, String> generateTableFiles(Map<String, Object> variables) {
        Map<String, String> files = new HashMap<>();

        String entityName = (String) variables.get("entityName");
        String uncapitalized = CodegenUtils.uncapitalize(entityName);
        variables.put("uncapitalized", uncapitalized);
        String packageName = (String) variables.get("packageName");
        boolean generateEntity = variables.containsKey("generateEntity");
        boolean generateDTO = variables.containsKey("generateDTO");
        Boolean generateController = (Boolean) variables.get("generateController");
        Boolean generateService = (Boolean) variables.get("generateService");
        Boolean generateMapper = (Boolean) variables.get("generateMapper");

        String basePath = "src/main/java/" + packageName.replace(".", "/");

        // 生成实体类 - 放到domain/entity包下
        ConditionHandler.branch(generateEntity, () ->
                files.put(basePath + "/domain/entity/" + entityName + ".java",
                        generateFromTemplate("templates/table/Entity.java.vm", variables)));
        // 生成DTO - 放到domain/dto包下
        ConditionHandler.branch(generateDTO, () ->
                files.put(basePath + "/domain/dto/" + entityName + "DTO.java",
                        generateFromTemplate("templates/table/DTO.java.vm", variables)));
        ConditionHandler.branch(generateMapper, () ->
                files.put(basePath + "/mapper/" + entityName + "Mapper.java",
                        generateFromTemplate("templates/table/Mapper.java.vm", variables)));
        ConditionHandler.branch(generateService, () ->
                files.put(basePath + "/service/" + entityName + "Service.java",
                        generateFromTemplate("templates/table/Service.java.vm", variables)));
        ConditionHandler.branch(generateService, () ->
                files.put(basePath + "/service/impl/" + entityName + "ServiceImpl.java",
                        generateFromTemplate("templates/table/ServiceImpl.java.vm", variables)));
        ConditionHandler.branch(generateController, () ->
                files.put(basePath + "/controller/" + entityName + "Controller.java",
                        generateFromTemplate("templates/table/Controller.java.vm", variables)));


        return files;
    }

    /**
     * 从模板生成代码
     */
    private String generateFromTemplate(String templatePath, Map<String, Object> variables) {
        try {
            Template template = velocityEngine.getTemplate(templatePath);
            VelocityContext context = new VelocityContext(variables);
            StringWriter writer = new StringWriter();
            template.merge(context, writer);

            return writer.toString();
        } catch (Exception e) {
            log.error("生成模板失败: {}", templatePath, e);
            throw new CustomerException("生成模板失败: " + e.getMessage());
        }
    }

}